/*
 * Systemprogrammierung
 * Multiplayer-Quiz
 *
 * Client
 * 
 * listener.c: Implementierung des Listener-Threads
 */

#define NULL 0 //NULL
#include "listener.h"
#include "gui/gui_interface.h"
#include "common/rfc.h"
#include "common/util.h"
#include <linux/stddef.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common/question.h"
#include "stdbool.h"
#include <stdio.h>
#include <unistd.h> //optind sollte da drin sein
#include <stdint.h> //uint8_t sollte eig kein Fehler mehr sein
#include <stddef.h> //NULL sollte kein Fehler mehr sein

#include "command.h"
#include <sys/types.h> //
#include <getopt.h>
#include <pthread.h>
#include <netdb.h>
#include "common/util.h"

#include "common/rfc.h"
#include "client/client.h"
#include <linux/stddef.h>
#include "common/util.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common/question.h"
#include "fragewechsel.h"
#include "stdbool.h"
#include <stdio.h>
#include <unistd.h>

#define MAX_NAME_LENGTH (32)
#define MAX_PLAYER              (6)

/*
 *      interne Prototypen
 */
void SetPlayerData(struct NET_MESSAGE* msg);
void DrawPlayerList(struct ST_GLOBAL_CLIENT_INFO* clientInfo);



void HandleError(struct NET_MESSAGE* msg);


struct ST_PLAYER_DATA
{
        char name[MAX_NAME_LENGTH];
        uint32_t score;
        uint8_t id;
};
struct ST_PLAYER_DATA players[MAX_PLAYER];

void *listener_thread(void *data)
{
        debugPrint("Listenerthread gestartet!");

        struct ST_GLOBAL_CLIENT_INFO* clientInfo = (struct ST_GLOBAL_CLIENT_INFO*) data;

        // zu Beginn in Vorbereitungsphase
        clientInfo->inPreperation = true;

        // Login Schleife!
        while (clientInfo->sock != 0)
        {
                // empfange Nachricht
                struct NET_MESSAGE recvdata;
                recvdata.header.type = 0;

                // Fehler beim Empfangen
                if (ReceiveRFCMsg(clientInfo->sock, &recvdata) < 0)
                {
                        debugPrint("Fehler beim Empfangen oder Gegenstelle geschlossen: beende Listener Thread!");
                        guiShowErrorDialog("Fehler beim Empfangen oder Gegenstelle geschlossen: beende Listener Thread!", 1);
                        return (NULL);
                }
                // korrekte RFC Nachricht empfangen
                else
                {
                        // switche auf Headertypen
                        switch (recvdata.header.type)
                        {

                        case TYPE_IS_LOGIN_RESPONSE_OK:
                                debugPrint("Login OK!");
                                break;


                        case TYPE_IS_PLAYER_LIST:
                                SetPlayerData(&recvdata);
                                DrawPlayerList(clientInfo);
                                break;

                        case TYPE_IS_ERROR:
                                HandleError(&recvdata);
                                break;

                        default:
                                break;
                        }
                }

                SecureFree(recvdata.data);
                recvdata.data = NULL;
        }

        // Thread beenden
        pthread_exit(NULL);
        return (NULL);
}


void SetPlayerData(struct NET_MESSAGE* msg)
{
        int offset = 0;
        int i;

        for (i = 0; i < MAX_PLAYER; i++)
        {
                if (offset < msg->header.size)
                {
                        // hole name und score und id
                        memmove(players[i].name, msg->data + offset, MAX_NAME_LENGTH);
                        memmove(&players[i].score, msg->data + offset + MAX_NAME_LENGTH, sizeof(players[i].score));
                        memmove(&players[i].id, msg->data + offset + MAX_NAME_LENGTH + sizeof(players[i].score), sizeof(players[i].id));

                        // ändere endianess
                        players[i].score = ntohl(players[i].score);

                        // schiebe offset weiter
                        offset += MAX_NAME_LENGTH + sizeof(players[i].score) + sizeof(players[i].id);

                }
                else
                {
                        strcpy(players[i].name, "");
                        players[i].score = 0;
                        players[i].id = 255;
                }
        }
}

void DrawPlayerList(struct ST_GLOBAL_CLIENT_INFO* clientInfo)
{
        // in der Vorbereitungsphase
        if (clientInfo->inPreperation == true)
        {

                // räume auf
                preparation_clearPlayers();

                // zeichne alle empfangenen Spieler
                int i;
                for (i = 0; i < MAX_PLAYER; i++)
                {
                        if (players[i].id != 255)
                        {
                                debugPrint("Spieler %s neu durch GUI gezeichnet", players[i].name);
                                preparation_addPlayer(players[i].name);
                        }
                }
        }

}

void HandleError(struct NET_MESSAGE* msg)
{
        char subtype = msg->data[0];
        char* errorMsg = (char*) Uint8Malloc(msg->header.size);
        strncpy(errorMsg, &msg->data[1], msg->header.size - 1);

        // reiche Fehler an GUI weiter
        guiShowErrorDialog(errorMsg, subtype);

        // Speicher freigeben
        SecureFree(errorMsg);
        errorMsg = NULL;
}

